package com.openlogic.flow.service.impl;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.dromara.warm.flow.core.dto.DefJson;
import org.dromara.warm.flow.core.entity.Definition;
import org.dromara.warm.flow.core.enums.NodeType;
import org.dromara.warm.flow.core.enums.PublishStatus;
import org.dromara.warm.flow.core.service.DefService;
import org.dromara.warm.flow.core.utils.AssertUtil;
import org.dromara.warm.flow.core.utils.CollUtil;
import org.dromara.warm.flow.core.utils.StreamUtils;
import org.dromara.warm.flow.orm.entity.FlowDefinition;
import org.dromara.warm.flow.orm.entity.FlowHisTask;
import org.dromara.warm.flow.orm.entity.FlowNode;
import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper;
import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
import org.dromara.warm.flow.orm.mapper.FlowSkipMapper;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.DownloadedFile;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.data.annotation.Tran;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.openlogic.common.core.exception.ServiceException;
import com.openlogic.common.core.web.domain.PageData;
import com.openlogic.flow.domain.query.FlowDefinitionQuery;
import com.openlogic.flow.domain.vo.FlowDefinitionVo;
import com.openlogic.flow.mapstruct.FlowDefinitionMapStruct;
import com.openlogic.flow.service.IFlowDefinitionServcie;
import com.openlogic.flow.utils.OpenLogicFLowUtils;

import cn.hutool.json.JSONUtil;

/**
 * @ClassName: OpenLogicFlowDeineServiceImpl
 * @Description: 流程定义Service实现
 * @author weiyongpeng
 * @date 2025年2月10日 下午7:49:16
 */
@Component
public class FlowDeinitionServiceImpl extends ServiceImpl<FlowDefinitionMapper, FlowDefinition> implements IFlowDefinitionServcie {

	private static final Logger log = LoggerFactory.getLogger(FlowDeinitionServiceImpl.class);
	
	@Inject
    private  DefService defService;
	
	@Inject
    private  FlowDefinitionMapper flowDefinitionMapper;
	
	@Inject
    private  FlowHisTaskMapper flowHisTaskMapper;
	
	@Inject
    private  FlowNodeMapper flowNodeMapper;
	
	@Inject
    private  FlowSkipMapper flowSkipMapper;
	
//	@Inject
//    private  FlwCategoryMapper flwCategoryMapper;
	
	@Inject
	private FlowDefinitionMapStruct flowDefinitionMapStruct;
    
	@Override
	public List<FlowDefinitionVo> queryList(FlowDefinition flowDefinition) {
		QueryWrapper wrapper = buildQueryWrapper(flowDefinition);
		wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey());
		return flowDefinitionMapStruct.toVO(flowDefinitionMapper.selectListByQuery(wrapper));
	}

	@Override
	public PageData<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition,
			Page<FlowDefinitionQuery> pageQuery) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean publish(Long id) {
		// 查询流程节点信息
		List<FlowNode> flowNodes = flowNodeMapper.selectListByQuery(QueryWrapper.create().and(FlowNode::getDefinitionId).eq(id));
        List<String> errorMsg = new ArrayList<>();
        if (CollUtil.isNotEmpty(flowNodes)) {
        	flowNodes.stream().forEach(flowNode -> {
        		// 申请人编码
        		 String applyNodeCode = OpenLogicFLowUtils.applyNodeCode(id);
        		/**
        		 * 申请人节点编码必须要等于当前流程节点的节点编码
        		 * 当前流转节点的节点类型必须是中间节点
        		 */
				if (StringUtils.isBlank(flowNode.getPermissionFlag())
						&& !String.valueOf(applyNodeCode).equals(flowNode.getNodeCode())
						&& flowNode.getNodeType().equals(NodeType.BETWEEN.getKey())) {
					errorMsg.add(flowNode.getNodeName());
				}
        	});
            if (CollUtil.isNotEmpty(errorMsg)) {
                throw new ServiceException("节点【" + StringUtils.join(errorMsg, ",") + "】未配置办理人!");
            }
        }
		return defService.publish(id);
	}

	@Override
	public void exportDef(Long id, Context ctx) throws IOException {
		// 查询流程定义
		Definition definitionFLow = defService.getById(id);
		AssertUtil.isNull(definitionFLow, "流程尚未定义：[" + id + "]");
		byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8);
		// 设置响应头和内容类型
		ctx.charset(StandardCharsets.UTF_8.name());
		ctx.outputAsFile(new DownloadedFile("text/json", data, StringUtils.join(definitionFLow.getFlowName(), ".json")));
	}

	@Override
	@Tran
	public boolean importJson(UploadedFile file, String category) {
		try {
			if (!file.isEmpty()) {
				byte[] contentAsBytes = file.getContentAsBytes();
				String jsonStr = new String(contentAsBytes);
				DefJson defJson = JSONUtil.toBean(jsonStr, DefJson.class);
				defJson.setCategory(category);
				defService.importDef(defJson);
				return true;
			} 
			log.error("读取文件流内容为空错误: {}", file.getName());
			throw new ServiceException("读取文件流内容为空错误: "+ file.getName());
		} catch (IOException e) {
			log.error("读取文件流错误: {}", e.getMessage(), e);
			throw new IllegalStateException("文件读取失败，请检查文件内容", e);
		}
	}

	@Override
	public boolean removeDef(List<Long> ids) {
		// 根据流程定义id批量查询流程历史，如果流程被使用，则无法删除流程定义
		QueryWrapper wrapper = QueryWrapper.create();
        wrapper.in(FlowHisTask::getDefinitionId, ids);
        List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectListByQuery(wrapper);
        if (CollUtil.isNotEmpty(flowHisTasks)) {
            List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectListByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId));
            if (CollUtil.isNotEmpty(flowDefinitions)) {
                String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
                log.error("流程定义【{}】已被使用不可被删除！", join);
                throw new ServiceException("流程定义【" + join + "】已被使用不可被删除！");
            }
        }
        try {
            defService.removeDef(ids);
        } catch (Exception e) {
            log.error("Error removing flow definitions: {}", e.getMessage());
            throw new RuntimeException("Failed to remove flow definitions", e);
        }
        return true;
	}

	@Override
	public void syncDef(String tenantId) {
		// TODO Auto-generated method stub
		
	}

    private QueryWrapper buildQueryWrapper(FlowDefinition flowDefinition) {
    	QueryWrapper wrapper = QueryWrapper.create();
    	wrapper.and(FlowDefinition::getFlowCode).like(flowDefinition.getFlowCode(), StringUtils.isNotBlank(flowDefinition.getFlowCode()));
    	wrapper.and(FlowDefinition::getFlowName).like(flowDefinition.getFlowName(), StringUtils.isNotBlank(flowDefinition.getFlowName()));
    	if (StringUtils.isNotBlank(flowDefinition.getCategory())) {
//          List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory()));
//          wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr));
      }
        wrapper.orderBy(FlowDefinition::getCreateTime).desc();
        return wrapper;
    }
}
